{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"float: right; margin: 0px 0px 0px 0px\"><img src=\"images/fish.jpg\" width=\"280px\"></div>\n",
    "\n",
    "## Anomaly Exploration (understanding 'Odd')\n",
    "In this notebook we're going to be using the zat Python module for processing, transformation and anomaly detection on Zeek network data. We're going to look at 'normal' http traffic and demonstrate the use of Isolation Forests for anomaly detection. We'll then explore those anomalies with clustering and PCA.\n",
    "\n",
    "**Software**\n",
    "- zat: https://github.com/SuperCowPowers/zat\n",
    "- Pandas: https://github.com/pandas-dev/pandas\n",
    "- Scikit-Learn: http://scikit-learn.org/stable/index.html\n",
    "\n",
    "**Techniques**\n",
    "- One Hot Encoding: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.get_dummies.html\n",
    "- Isolation Forest: http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html\n",
    "- PCA: http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html\n",
    "\n",
    "**Related Notebooks**\n",
    "- Zeek to Scikit-Learn: https://nbviewer.jupyter.org/github/SuperCowPowers/zat/blob/master/notebooks/Zeek_to_Scikit_Learn.ipynb\n",
    "\n",
    "**Note:** A previous version of this notebook used a large http log (1 million rows) but we wanted people to be able to run the notebook themselves, so we've changed it to run on the local example http.log."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "zat: 0.3.6\n",
      "Pandas: 0.25.1\n",
      "Numpy: 1.16.4\n",
      "Scikit Learn Version: 0.21.2\n"
     ]
    }
   ],
   "source": [
    "import zat\n",
    "from zat.log_to_dataframe import LogToDataFrame\n",
    "from zat.dataframe_to_matrix import DataFrameToMatrix\n",
    "print('zat: {:s}'.format(zat.__version__))\n",
    "import pandas as pd\n",
    "print('Pandas: {:s}'.format(pd.__version__))\n",
    "import numpy as np\n",
    "print('Numpy: {:s}'.format(np.__version__))\n",
    "import sklearn\n",
    "from sklearn.ensemble import IsolationForest\n",
    "from sklearn.decomposition import PCA\n",
    "from sklearn.cluster import KMeans\n",
    "print('Scikit Learn Version:', sklearn.__version__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Read in 150 Rows...\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>uid</th>\n",
       "      <th>id.orig_h</th>\n",
       "      <th>id.orig_p</th>\n",
       "      <th>id.resp_h</th>\n",
       "      <th>id.resp_p</th>\n",
       "      <th>trans_depth</th>\n",
       "      <th>method</th>\n",
       "      <th>host</th>\n",
       "      <th>uri</th>\n",
       "      <th>referrer</th>\n",
       "      <th>...</th>\n",
       "      <th>info_msg</th>\n",
       "      <th>filename</th>\n",
       "      <th>tags</th>\n",
       "      <th>username</th>\n",
       "      <th>password</th>\n",
       "      <th>proxied</th>\n",
       "      <th>orig_fuids</th>\n",
       "      <th>orig_mime_types</th>\n",
       "      <th>resp_fuids</th>\n",
       "      <th>resp_mime_types</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ts</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:27.668081999</td>\n",
       "      <td>CyIaMO7IheOh38Zsi</td>\n",
       "      <td>192.168.33.10</td>\n",
       "      <td>1031</td>\n",
       "      <td>54.245.228.191</td>\n",
       "      <td>80</td>\n",
       "      <td>1</td>\n",
       "      <td>GET</td>\n",
       "      <td>guyspy.com</td>\n",
       "      <td>/</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>(empty)</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>Fnjq3r4R0VGmHVWiN5</td>\n",
       "      <td>text/html</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:27.731701851</td>\n",
       "      <td>CoyZrY2g74UvMMgp4a</td>\n",
       "      <td>192.168.33.10</td>\n",
       "      <td>1032</td>\n",
       "      <td>54.245.228.191</td>\n",
       "      <td>80</td>\n",
       "      <td>1</td>\n",
       "      <td>GET</td>\n",
       "      <td>www.guyspy.com</td>\n",
       "      <td>/</td>\n",
       "      <td>NaN</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>(empty)</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>FCQ5aX37YzsjAKpcv8</td>\n",
       "      <td>text/html</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:28.092921972</td>\n",
       "      <td>CoyZrY2g74UvMMgp4a</td>\n",
       "      <td>192.168.33.10</td>\n",
       "      <td>1032</td>\n",
       "      <td>54.245.228.191</td>\n",
       "      <td>80</td>\n",
       "      <td>2</td>\n",
       "      <td>GET</td>\n",
       "      <td>www.guyspy.com</td>\n",
       "      <td>/wp-content/plugins/slider-pro/css/advanced-sl...</td>\n",
       "      <td>http://www.guyspy.com/</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>(empty)</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>FD9Xu815Hwui3sniSf</td>\n",
       "      <td>text/html</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:28.150300980</td>\n",
       "      <td>CiCKTz4e0fkYYazBS3</td>\n",
       "      <td>192.168.33.10</td>\n",
       "      <td>1040</td>\n",
       "      <td>54.245.228.191</td>\n",
       "      <td>80</td>\n",
       "      <td>1</td>\n",
       "      <td>GET</td>\n",
       "      <td>www.guyspy.com</td>\n",
       "      <td>/wp-content/plugins/contact-form-7/includes/cs...</td>\n",
       "      <td>http://www.guyspy.com/</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>(empty)</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>FMZXWm1yCdsCAU3K9d</td>\n",
       "      <td>text/plain</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:28.150601864</td>\n",
       "      <td>C1YBkC1uuO9bzndRvh</td>\n",
       "      <td>192.168.33.10</td>\n",
       "      <td>1041</td>\n",
       "      <td>54.245.228.191</td>\n",
       "      <td>80</td>\n",
       "      <td>1</td>\n",
       "      <td>GET</td>\n",
       "      <td>www.guyspy.com</td>\n",
       "      <td>/wp-content/plugins/slider-pro/css/slider/adva...</td>\n",
       "      <td>http://www.guyspy.com/</td>\n",
       "      <td>...</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>(empty)</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>NaN</td>\n",
       "      <td>FA4NM039Rf9Y8Sn2Rh</td>\n",
       "      <td>text/plain</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 26 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                              uid      id.orig_h  id.orig_p  \\\n",
       "ts                                                                            \n",
       "2013-09-15 23:44:27.668081999   CyIaMO7IheOh38Zsi  192.168.33.10       1031   \n",
       "2013-09-15 23:44:27.731701851  CoyZrY2g74UvMMgp4a  192.168.33.10       1032   \n",
       "2013-09-15 23:44:28.092921972  CoyZrY2g74UvMMgp4a  192.168.33.10       1032   \n",
       "2013-09-15 23:44:28.150300980  CiCKTz4e0fkYYazBS3  192.168.33.10       1040   \n",
       "2013-09-15 23:44:28.150601864  C1YBkC1uuO9bzndRvh  192.168.33.10       1041   \n",
       "\n",
       "                                    id.resp_h  id.resp_p  trans_depth method  \\\n",
       "ts                                                                             \n",
       "2013-09-15 23:44:27.668081999  54.245.228.191         80            1    GET   \n",
       "2013-09-15 23:44:27.731701851  54.245.228.191         80            1    GET   \n",
       "2013-09-15 23:44:28.092921972  54.245.228.191         80            2    GET   \n",
       "2013-09-15 23:44:28.150300980  54.245.228.191         80            1    GET   \n",
       "2013-09-15 23:44:28.150601864  54.245.228.191         80            1    GET   \n",
       "\n",
       "                                         host  \\\n",
       "ts                                              \n",
       "2013-09-15 23:44:27.668081999      guyspy.com   \n",
       "2013-09-15 23:44:27.731701851  www.guyspy.com   \n",
       "2013-09-15 23:44:28.092921972  www.guyspy.com   \n",
       "2013-09-15 23:44:28.150300980  www.guyspy.com   \n",
       "2013-09-15 23:44:28.150601864  www.guyspy.com   \n",
       "\n",
       "                                                                             uri  \\\n",
       "ts                                                                                 \n",
       "2013-09-15 23:44:27.668081999                                                  /   \n",
       "2013-09-15 23:44:27.731701851                                                  /   \n",
       "2013-09-15 23:44:28.092921972  /wp-content/plugins/slider-pro/css/advanced-sl...   \n",
       "2013-09-15 23:44:28.150300980  /wp-content/plugins/contact-form-7/includes/cs...   \n",
       "2013-09-15 23:44:28.150601864  /wp-content/plugins/slider-pro/css/slider/adva...   \n",
       "\n",
       "                                             referrer  ... info_msg  filename  \\\n",
       "ts                                                     ...                      \n",
       "2013-09-15 23:44:27.668081999                     NaN  ...      NaN       NaN   \n",
       "2013-09-15 23:44:27.731701851                     NaN  ...      NaN       NaN   \n",
       "2013-09-15 23:44:28.092921972  http://www.guyspy.com/  ...      NaN       NaN   \n",
       "2013-09-15 23:44:28.150300980  http://www.guyspy.com/  ...      NaN       NaN   \n",
       "2013-09-15 23:44:28.150601864  http://www.guyspy.com/  ...      NaN       NaN   \n",
       "\n",
       "                                  tags  username password  proxied orig_fuids  \\\n",
       "ts                                                                              \n",
       "2013-09-15 23:44:27.668081999  (empty)       NaN      NaN      NaN        NaN   \n",
       "2013-09-15 23:44:27.731701851  (empty)       NaN      NaN      NaN        NaN   \n",
       "2013-09-15 23:44:28.092921972  (empty)       NaN      NaN      NaN        NaN   \n",
       "2013-09-15 23:44:28.150300980  (empty)       NaN      NaN      NaN        NaN   \n",
       "2013-09-15 23:44:28.150601864  (empty)       NaN      NaN      NaN        NaN   \n",
       "\n",
       "                              orig_mime_types          resp_fuids  \\\n",
       "ts                                                                  \n",
       "2013-09-15 23:44:27.668081999             NaN  Fnjq3r4R0VGmHVWiN5   \n",
       "2013-09-15 23:44:27.731701851             NaN  FCQ5aX37YzsjAKpcv8   \n",
       "2013-09-15 23:44:28.092921972             NaN  FD9Xu815Hwui3sniSf   \n",
       "2013-09-15 23:44:28.150300980             NaN  FMZXWm1yCdsCAU3K9d   \n",
       "2013-09-15 23:44:28.150601864             NaN  FA4NM039Rf9Y8Sn2Rh   \n",
       "\n",
       "                              resp_mime_types  \n",
       "ts                                             \n",
       "2013-09-15 23:44:27.668081999       text/html  \n",
       "2013-09-15 23:44:27.731701851       text/html  \n",
       "2013-09-15 23:44:28.092921972       text/html  \n",
       "2013-09-15 23:44:28.150300980      text/plain  \n",
       "2013-09-15 23:44:28.150601864      text/plain  \n",
       "\n",
       "[5 rows x 26 columns]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Create a Pandas dataframe from the Zeek HTTP log\n",
    "log_to_df = LogToDataFrame()\n",
    "zeek_df = log_to_df.create_dataframe('../data/http.log')\n",
    "print('Read in {:d} Rows...'.format(len(zeek_df)))\n",
    "zeek_df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"float: left; margin: 20px -10px 0px -40px\"><img src=\"images/confused.jpg\" width=\"200px\"></div>\n",
    "<div style=\"float: right; margin: 20px -10px 0px -10px\"><img src=\"images/pandas.png\" width=\"300px\"></div>\n",
    "## So... what just happened?\n",
    "**Yep it was quick... the two little lines of code above turned a Zeek log (any log) into a Pandas DataFrame. The zat package also supports streaming data from dynamic/active logs, handles log rotations and in general tries to make your life a bit easier when doing data analysis and machine learning on Zeek data.**\n",
    "\n",
    "**Now that we have the data in a dataframe there are a million wonderful things we could do for data munging, processing and analysis but that will have to wait for another time/notebook.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We're going to pick some features that might be interesting\n",
    "# some of the features are numerical and some are categorical\n",
    "features = ['id.resp_p', 'method', 'resp_mime_types', 'request_body_len']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Our HTTP features are a mix of numeric and categorical data\n",
    "When we look at the http records some of the data is numerical and some of it is categorical so we'll need a way of handling both data types in a generalized way. zat has a DataFrameToMatrix class that handles a lot of the details and mechanics of combining numerical and categorical data, we'll use below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>id.resp_p</th>\n",
       "      <th>method</th>\n",
       "      <th>resp_mime_types</th>\n",
       "      <th>request_body_len</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ts</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:27.668081999</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>text/html</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:27.731701851</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>text/html</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:28.092921972</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>text/html</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:28.150300980</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>text/plain</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:28.150601864</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>text/plain</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                               id.resp_p method resp_mime_types  \\\n",
       "ts                                                                \n",
       "2013-09-15 23:44:27.668081999         80    GET       text/html   \n",
       "2013-09-15 23:44:27.731701851         80    GET       text/html   \n",
       "2013-09-15 23:44:28.092921972         80    GET       text/html   \n",
       "2013-09-15 23:44:28.150300980         80    GET      text/plain   \n",
       "2013-09-15 23:44:28.150601864         80    GET      text/plain   \n",
       "\n",
       "                               request_body_len  \n",
       "ts                                               \n",
       "2013-09-15 23:44:27.668081999                 0  \n",
       "2013-09-15 23:44:27.731701851                 0  \n",
       "2013-09-15 23:44:28.092921972                 0  \n",
       "2013-09-15 23:44:28.150300980                 0  \n",
       "2013-09-15 23:44:28.150601864                 0  "
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Show the dataframe with mixed feature types\n",
    "zeek_df[features].head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"float: right; margin: -10px 40px -10px 40px\"><img src=\"images/transformers.png\" width=\"200px\"></div>\n",
    "\n",
    "## Transformers\n",
    "**We'll now use a scikit-learn tranformer class to convert the Pandas DataFrame to a numpy ndarray (matrix). Yes it's awesome... I'm not sure it's Optimus Prime awesome.. but it's still pretty nice.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Normalizing column id.resp_p...\n",
      "Normalizing column request_body_len...\n",
      "(150, 12)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[0., 0., 1., 0., 0., 1., 0., 0., 0., 0., 0., 0.]], dtype=float32)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Use the zat DataframeToMatrix class (handles categorical data)\n",
    "# You can see below it uses a heuristic to detect category data. When doing\n",
    "# this for real we should explicitly convert before sending to the transformer.\n",
    "to_matrix = DataFrameToMatrix()\n",
    "zeek_matrix = to_matrix.fit_transform(zeek_df[features], normalize=True)\n",
    "print(zeek_matrix.shape)\n",
    "zeek_matrix[:1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "IsolationForest(behaviour='new', bootstrap=False, contamination=0.25,\n",
       "                max_features=1.0, max_samples='auto', n_estimators=100,\n",
       "                n_jobs=None, random_state=None, verbose=0, warm_start=False)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Train/fit and Predict anomalous instances using the Isolation Forest model\n",
    "odd_clf = IsolationForest(behaviour='new', contamination=0.25) # Marking 25% odd\n",
    "odd_clf.fit(zeek_matrix)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(32, 4)\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>id.resp_p</th>\n",
       "      <th>method</th>\n",
       "      <th>resp_mime_types</th>\n",
       "      <th>request_body_len</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ts</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:47.464160919</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:47.464160919</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:49.221977949</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:50.805350065</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:51.404618979</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                               id.resp_p method        resp_mime_types  request_body_len\n",
       "ts                                                                                      \n",
       "2013-09-15 23:44:47.464160919         80    GET  application/x-dosexec                 0\n",
       "2013-09-15 23:44:47.464160919         80    GET  application/x-dosexec                 0\n",
       "2013-09-15 23:44:49.221977949         80    GET  application/x-dosexec                 0\n",
       "2013-09-15 23:44:50.805350065         80    GET  application/x-dosexec                 0\n",
       "2013-09-15 23:44:51.404618979         80    GET  application/x-dosexec                 0"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Now we create a new dataframe using the prediction from our classifier\n",
    "odd_df = zeek_df[features][odd_clf.predict(zeek_matrix) == -1]\n",
    "print(odd_df.shape)\n",
    "odd_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Normalizing column id.resp_p...\n",
      "Normalizing column request_body_len...\n"
     ]
    }
   ],
   "source": [
    "# Now we're going to explore our odd dataframe with help from KMeans and PCA algorithms\n",
    "odd_matrix = to_matrix.fit_transform(odd_df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>id.resp_p</th>\n",
       "      <th>method</th>\n",
       "      <th>resp_mime_types</th>\n",
       "      <th>request_body_len</th>\n",
       "      <th>x</th>\n",
       "      <th>y</th>\n",
       "      <th>cluster</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ts</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:47.464160919</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "      <td>1.112838</td>\n",
       "      <td>-0.615773</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:47.464160919</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "      <td>1.112838</td>\n",
       "      <td>-0.615774</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:49.221977949</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "      <td>1.112838</td>\n",
       "      <td>-0.615773</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:50.805350065</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "      <td>1.112838</td>\n",
       "      <td>-0.615774</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2013-09-15 23:44:51.404618979</td>\n",
       "      <td>80</td>\n",
       "      <td>GET</td>\n",
       "      <td>application/x-dosexec</td>\n",
       "      <td>0</td>\n",
       "      <td>1.112838</td>\n",
       "      <td>-0.615774</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                               id.resp_p method        resp_mime_types  request_body_len         x         y  cluster\n",
       "ts                                                                                                                   \n",
       "2013-09-15 23:44:47.464160919         80    GET  application/x-dosexec                 0  1.112838 -0.615773        0\n",
       "2013-09-15 23:44:47.464160919         80    GET  application/x-dosexec                 0  1.112838 -0.615774        0\n",
       "2013-09-15 23:44:49.221977949         80    GET  application/x-dosexec                 0  1.112838 -0.615773        0\n",
       "2013-09-15 23:44:50.805350065         80    GET  application/x-dosexec                 0  1.112838 -0.615774        0\n",
       "2013-09-15 23:44:51.404618979         80    GET  application/x-dosexec                 0  1.112838 -0.615774        0"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Just some simple stuff for this example, KMeans and PCA\n",
    "kmeans = KMeans(n_clusters=4).fit_predict(odd_matrix)  # Change this to 3/5 for fun\n",
    "pca = PCA(n_components=3).fit_transform(odd_matrix)\n",
    "\n",
    "# Now we can put our ML results back onto our dataframe!\n",
    "odd_df['x'] = pca[:, 0] # PCA X Column\n",
    "odd_df['y'] = pca[:, 1] # PCA Y Column\n",
    "odd_df['cluster'] = kmeans\n",
    "odd_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Plotting defaults\n",
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams['font.size'] = 14.0\n",
    "plt.rcParams['figure.figsize'] = 15.0, 6.0\n",
    "\n",
    "# Helper method for scatter/beeswarm plot\n",
    "def jitter(arr):\n",
    "    stdev = .02*(max(arr)-min(arr))\n",
    "    return arr + np.random.randn(len(arr)) * stdev"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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cuVKXnjhBRYtWsS9997L7373O84666xO79nS0sKFF17I97///SOuDRt26MiawYMH96jWjp555hk+85nP8L3vfY8/+7M/O657ZWJwlCRJOtUUTUjTQvfUprD2wduQNwSaD6TAN6AgBbn3fwODx8HQiSk40m6aYQhp99T2oXDLi2ld44CBaSRy//vdrymvONWhU1NhYTqnMb/j2thuaG5O/Y/TsGHDmD17Ng899BB33XXXEescd+zY0eU6x9LSUjZv3nzweV1d3WHPAXJzc5kxYwYzZszgq1/96sEpp5///OcZOHAgzc3Nh7WfOnUq//t//29GjBhxXOsrM/nhD3/ILbfcwhNPPMEnP3nEsfW9Kts3x5EkSdKxCCGN7o2/BS68Hy7+e7hkCfzxY3DJQ1Dx92mEseTCFOroxtq02JgCIwADDj838qj15KSprjo1TZwIO3YcvV1nduyAc889ertuWLJkCTFGKioqePrpp6muruatt97iu9/9LhdccEGX/WbMmMGSJUuoqqpizZo1zJs3j4J2I6jLly/nwQcfZM2aNdTW1vLUU0+xa9eug+spy8vLefPNN6murmbbtm00NjZy8803M2rUKK677joqKyupqalh5cqVfPGLXzxsZ9XO/PjHP2bSpEls2rSpyzbf//73ufnmm/m7v/s7/vRP/5QtW7awZcsW6uvre/hT6x6DoyRJ0ukqp7CH4S+v9YgPgJY05bW7YnN6P52apk1LI449XWcYY+o3bVqvlDF+/HhWr17NrFmzuOeee7jggguYMWMGP/nJT3j00Ue77PfNb36T8ePHM336dD75yU/yuc99jpEjRx68XlxczLPPPsvMmTOZNGkSDzzwAI899hiXX345ALfeeiuTJ0+moqKC0tJSXn31VQYNGsTKlSsZP348N954I5MmTeKWW25h+/btR935dOfOnVRXVx82Xbajhx9+mKamJr7whS8wevTog48bbrihhz+17gl9uYj0ZFJRURGrqqr6uwxJkqQT5/88AVtfgcIx3Wu//XVo2JjOaWz6IG2CU3KU9Y1t9m6C0svSCKhOCuvWrev+DqUxwsKFsH07tFu/d1T19elIjoUL3XH3BMn05xpCWBVjrOjsmiOOkiRJp6uR09IRHN0dSBhcnkYc2x6Dy7vXL8b0PiN7Z1RJWSgEmDsXdu2CdmcUZtTQALt3p36Gxqxn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\n",
      "text/plain": [
       "<Figure size 1080x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Jitter so we can see instances that are projected coincident in 2D\n",
    "odd_df['jx'] = jitter(odd_df['x'])\n",
    "odd_df['jy'] = jitter(odd_df['y'])\n",
    "\n",
    "# Now use dataframe group by cluster\n",
    "cluster_groups = odd_df.groupby('cluster')\n",
    "\n",
    "# Plot the Machine Learning results\n",
    "colors = {0:'green', 1:'blue', 2:'red', 3:'orange', 4:'purple', 5:'brown'}\n",
    "fig, ax = plt.subplots()\n",
    "for key, group in cluster_groups:\n",
    "    group.plot(ax=ax, kind='scatter', x='jx', y='jy', alpha=0.5, s=250,\n",
    "               label='Cluster: {:d}'.format(key), color=colors[key])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Cluster 0: 8 observations\n",
      "                               id.resp_p method        resp_mime_types  request_body_len\n",
      "ts                                                                                      \n",
      "2013-09-15 23:44:47.464160919         80    GET  application/x-dosexec                 0\n",
      "2013-09-15 23:44:47.464160919         80    GET  application/x-dosexec                 0\n",
      "2013-09-15 23:44:49.221977949         80    GET  application/x-dosexec                 0\n",
      "2013-09-15 23:44:50.805350065         80    GET  application/x-dosexec                 0\n",
      "2013-09-15 23:44:51.404618979         80    GET  application/x-dosexec                 0\n",
      "\n",
      "Cluster 1: 7 observations\n",
      "                               id.resp_p   method resp_mime_types  request_body_len\n",
      "ts                                                                                 \n",
      "2013-09-15 23:48:06.495719910         80  OPTIONS      text/plain                 0\n",
      "2013-09-15 23:48:07.495719910         80  OPTIONS      text/plain                 0\n",
      "2013-09-15 23:48:08.495719910         80  OPTIONS      text/plain                 0\n",
      "2013-09-15 23:48:08.495719910         80  OPTIONS      text/plain                 0\n",
      "2013-09-15 23:48:08.495719910         80  OPTIONS      text/plain                 0\n",
      "\n",
      "Cluster 2: 10 observations\n",
      "                               id.resp_p method resp_mime_types  request_body_len\n",
      "ts                                                                               \n",
      "2013-09-15 23:48:10.495719910         80   POST      text/plain             69823\n",
      "2013-09-15 23:48:11.495719910         80   POST      text/plain             69993\n",
      "2013-09-15 23:48:12.495719910         80   POST      text/plain             71993\n",
      "2013-09-15 23:48:13.495719910         80   POST      text/plain             70993\n",
      "2013-09-15 23:48:14.495719910         80   POST      text/plain             72993\n",
      "\n",
      "Cluster 3: 7 observations\n",
      "                               id.resp_p method resp_mime_types  request_body_len\n",
      "ts                                                                               \n",
      "2013-09-15 23:48:03.495719910       8080    GET      text/plain                 0\n",
      "2013-09-15 23:48:04.495719910       8080    GET      text/plain                 0\n",
      "2013-09-15 23:48:04.495719910       8080    GET      text/plain                 0\n",
      "2013-09-15 23:48:04.495719910       8080    GET      text/plain                 0\n",
      "2013-09-15 23:48:04.495719910       8080    GET      text/plain                 0\n"
     ]
    }
   ],
   "source": [
    "# Now print out the details for each cluster\n",
    "pd.set_option('display.width', 1000)\n",
    "for key, group in cluster_groups:\n",
    "    print('\\nCluster {:d}: {:d} observations'.format(key, len(group)))\n",
    "    print(group[features].head())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### <div style=\"float: right; margin: 10px 10px 10px 10px\"><img src=\"images/deep_dive.jpeg\" width=\"250px\"></div>\n",
    "## Categorical variables that are anomalous\n",
    "- Cluster 0: application/x-dosexec mime_types\n",
    "- Cluster 1: http method of OPTIONS (instead of normal GET/POST)\n",
    "- Cluster 2: See Below\n",
    "- Cluster 3: response port of 8080 (instead of 80)\n",
    "\n",
    "## Numerical variable outliers\n",
    "- Cluster 2: The request_body_len values are outliers (for this demo dataset)\n",
    "\n",
    "**The important thing here is that both categorical and numerical variables were properly handled and the machine learning algorithm 'did the right thing' when marking outliers (for categorical and numerical fields)**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "For this small demo dataset almost all request_body_len are 0\n",
      "Cluster 2 represents outliers\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1080x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Distribution of the request body length\n",
    "Zeek_df[['request_body_len']].hist()\n",
    "print('\\nFor this small demo dataset almost all request_body_len are 0\\nCluster 2 represents outliers')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div style=\"float: right; margin: 20px 20px 20px 20px\"><img src=\"images/why_normal.jpg\" width=\"200px\"></div>\n",
    "\n",
    "## The anomalies identified by the model might be fine/expected\n",
    "Looking at the anomalous clusters for this small demo http log reveals four clusters that may be perfectly fine.  So\n",
    "here we're not equating anomalous with 'bad'. The use of an anomaly detection algorithm can bring latent issues to the attention of threat hunters and system administrations. The results might be expected or a misconfigured appliance or something more nefarious that needs attention from security.\n",
    "\n",
    "\n",
    "If you liked this notebook please visit the [zat](https://github.com/SuperCowPowers/zat) project for more notebooks and examples.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
